package de.medieninf.android.sensimg;

import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;

public class ImageViewActivity extends Activity  {
	final static String TAG = "ImageViewActivity";
	final static int UPDATE_IMAGE = 42;
	
	SensorService mSensorService;

	private ImageView mImageView;
	private volatile ImageLoader mImageLoader; // set to null to stop
	private Object bitmapLock = new Object();
	private Bitmap bitmap;
	private String host;
	private int port;
	KeyboardState keyboardState;
	
	private Handler updateHandler = new UpdateHandler(this);
	private static class UpdateHandler extends Handler {
		private WeakReference<ImageViewActivity> imageViewActivityRef;
		
		UpdateHandler(ImageViewActivity imageViewActivity) {
			imageViewActivityRef = new WeakReference<ImageViewActivity>(imageViewActivity);
	    }
		
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case UPDATE_IMAGE:
				ImageViewActivity imageViewActivity = imageViewActivityRef.get();
				if (imageViewActivity != null) {
					imageViewActivity.mImageView.invalidate();
				}
				break;
			}
			super.handleMessage(msg);
		}
	};
	
    private ServiceConnection mConnection = new ServiceConnection() {
    	@Override
        public void onServiceConnected(ComponentName className, IBinder service) {
    		// Log.v(TAG, "trying to bind SensorService");
            mSensorService = ((SensorService.LocalBinder) service).getService();
            keyboardState = mSensorService.getKeyboardState();
            host = mSensorService.getCurrentHostRetrieve();
            port = mSensorService.getCurrentPortRetrieve();
    		mImageLoader = new ImageLoader();
    		mImageLoader.setWidthHeight(mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
            mImageLoader.start();
            // Log.v(TAG, "ImageLoader started");
        }
		@Override
		public void onServiceDisconnected(ComponentName name) {
    		// Log.v(TAG, "SensorService is disconnected");
			mSensorService = null;
		}
    };
	
	private class ImageView extends View {
		// final static String TAG = "ImageView";
		int width=0;
		int height=0;
		Paint paint;

		public ImageView(Context context) {
			super(context);
			init();
		}
		
		public ImageView(Context context, AttributeSet attrs) {
			super(context, attrs);
			init();
		}

		public ImageView(Context context, AttributeSet attrs, int defStyle) {
			super(context, attrs, defStyle);
			init();
		}

		private void init() {
			paint = new Paint();
			paint.setColor(Color.RED);
			setFocusable(true); // important for key events
			setFocusableInTouchMode(true);
			requestFocus(); // make sure we have focus
			keyboardState = new KeyboardState();
		}
		
		@Override
		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
			super.onMeasure(widthMeasureSpec, heightMeasureSpec);
			width = MeasureSpec.getSize(widthMeasureSpec);
			height = MeasureSpec.getSize(heightMeasureSpec);
			// Log.v(TAG, "in onMeasure " + width + "x" + height);
			mImageLoader.setWidthHeight(width, height);
		}
				
		@Override
		protected void onDraw(Canvas canvas) {
	        canvas.drawColor(Color.WHITE);
	        Bitmap bitmapRef;
	        synchronized (bitmapLock) {
				bitmapRef = bitmap;
			}
	        if (bitmapRef != null) {
	        	canvas.drawBitmap(bitmapRef, 0.0f, 0.0f, paint);
	        	// Log.v(TAG, "drawn Bitmap");
	        }
		}
		
		@Override
		public boolean onKeyDown(int keyCode, KeyEvent event) {
			if (keyboardState != null)
				keyboardState.onKeyDown(keyCode, event);
			// Log.v(TAG, "String :" + keyboardState.getKeys());
			return super.onKeyDown(keyCode, event);
		}

		@Override
		public boolean onKeyUp(int keyCode, KeyEvent event) {
			if (keyboardState != null)
				keyboardState.onKeyUp(keyCode, event);
			// Log.v(TAG, "String :" + keyboardState.getKeys());
			return super.onKeyUp(keyCode, event);
		}
		
	}

	private class ImageLoader extends Thread {
		private int width;
		private int height;
		private String type;
		private volatile String query;

		public ImageLoader() {
			// G1
			width = 320;
			height = 480;
			type = "JPEG";
			updateQuery();
		}

		private void doSleep(int msecs) {
			try {
				Thread.sleep(msecs);
			} catch (InterruptedException e) {
				// ignore
			}
		}
		
		@Override
		public void run() {
			String baseUrl = "http://" + host + ":" + port + "/";
			if (host == null || host.equals("")) {
				Log.w(TAG, "ImageLoader: host is empty");
				return;
			}
			while (mImageLoader == Thread.currentThread()) {
				// Log.v(TAG, "try retrieve one");
				try {
					URL url = new URL(baseUrl+query);
					HttpURLConnection connection = (HttpURLConnection) url.openConnection();
					connection.setConnectTimeout(2000); // 2 seconds timeout
					connection.setRequestMethod("GET");
					InputStream bis = connection.getInputStream();
					synchronized (bitmapLock) {
						bitmap = BitmapFactory.decodeStream(bis);						
					}
					// Log.v(TAG, "read image");
					updateHandler.sendEmptyMessage(UPDATE_IMAGE);
				} catch (MalformedURLException e) {
					Log.w(TAG, "malformed URL exception " + e.getMessage());
					doSleep(200);
				} catch (SocketTimeoutException e) {
					Log.w(TAG, "SocketTimeoutException " + e.getMessage());
					doSleep(200);
				} catch (IOException e) {
					Log.w(TAG, "IOException " + e.getMessage());
					doSleep(200);
				}
			}
		}
		
		public void setWidthHeight(int width, int height) {
			this.width = width;
			this.height = height;
			updateQuery();
		}
		
		/*
		public void setType(String type) {
			this.type = type;
			updateQuery();
		}
		*/
		
		private void updateQuery() {
			String localQuery = "?width=" + width + "&height=" + height + "&type=" + type;
			query = localQuery;
		}
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mImageView = new ImageView(this);
		setContentView(mImageView);
        bindService(
        		new Intent(this, SensorService.class),
                mConnection,
                Context.BIND_AUTO_CREATE);
	}
	
	@Override
	protected void onPause() {
		mImageLoader = null;
		super.onPause();
	}
	
	@Override
	protected void onResume() {
		mImageLoader = new ImageLoader();
		mImageLoader.start();
		super.onResume();
	}
	
	@Override
	protected void onDestroy() {
		mImageLoader = null;
		unbindService(mConnection);
		super.onDestroy();
	}

}
